﻿using System;
using System.Collections.Generic;

namespace NetTopologySuite.Index.Bintree
{
	[Serializable]
	public abstract class NodeBase<T>
	{
		public static int GetSubnodeIndex(Interval interval, double centre)
		{
			int result = -1;
			if (interval.Min >= centre)
			{
				result = 1;
			}
			if (interval.Max <= centre)
			{
				result = 0;
			}
			return result;
		}

		public IList<T> Items
		{
			get
			{
				return this._items;
			}
			protected set
			{
				this._items = value;
			}
		}

		public void Add(T item)
		{
			this._items.Add(item);
		}

		public IList<T> AddAllItems(IList<T> items)
		{
			foreach (T item in this._items)
			{
				items.Add(item);
			}
			for (int i = 0; i < 2; i++)
			{
				if (this.Subnode[i] != null)
				{
					this.Subnode[i].AddAllItems(items);
				}
			}
			return items;
		}

		protected abstract bool IsSearchMatch(Interval interval);

		public void AddAllItemsFromOverlapping(Interval interval, ICollection<T> resultItems)
		{
			if (interval != null && !this.IsSearchMatch(interval))
			{
				return;
			}
			foreach (T item in this._items)
			{
				resultItems.Add(item);
			}
			if (this.Subnode[0] != null)
			{
				this.Subnode[0].AddAllItemsFromOverlapping(interval, resultItems);
			}
			if (this.Subnode[1] != null)
			{
				this.Subnode[1].AddAllItemsFromOverlapping(interval, resultItems);
			}
		}

		public bool Remove(Interval itemInterval, T item)
		{
			if (!this.IsSearchMatch(itemInterval))
			{
				return false;
			}
			bool flag = false;
			for (int i = 0; i < 2; i++)
			{
				if (this.Subnode[i] != null)
				{
					flag = this.Subnode[i].Remove(itemInterval, item);
					if (flag)
					{
						if (this.Subnode[i].IsPrunable)
						{
							this.Subnode[i] = null;
							break;
						}
						break;
					}
				}
			}
			return flag || this._items.Remove(item);
		}

		public bool IsPrunable
		{
			get
			{
				return !this.HasChildren && !this.HasItems;
			}
		}

		public bool HasChildren
		{
			get
			{
				for (int i = 0; i < 2; i++)
				{
					if (this.Subnode[i] != null)
					{
						return true;
					}
				}
				return false;
			}
		}

		public bool HasItems
		{
			get
			{
				return this._items.Count != 0;
			}
		}

		public int Depth
		{
			get
			{
				int num = 0;
				for (int i = 0; i < 2; i++)
				{
					if (this.Subnode[i] != null)
					{
						int depth = this.Subnode[i].Depth;
						if (depth > num)
						{
							num = depth;
						}
					}
				}
				return num + 1;
			}
		}

		public int Count
		{
			get
			{
				int num = 0;
				for (int i = 0; i < 2; i++)
				{
					if (this.Subnode[i] != null)
					{
						num += this.Subnode[i].Count;
					}
				}
				return num + this._items.Count;
			}
		}

		public int NodeCount
		{
			get
			{
				int num = 0;
				for (int i = 0; i < 2; i++)
				{
					if (this.Subnode[i] != null)
					{
						num += this.Subnode[i].NodeCount;
					}
				}
				return num + 1;
			}
		}

		private IList<T> _items = new List<T>();

		protected Node<T>[] Subnode = new Node<T>[2];
	}
}
